所有由oldseedling发布的文章

! [remote rejected] master -> master (unpacker error) 解决办法

今天 push 到自己搭建的 git 服务器时遇到了这个错误。

remote: error: insufficient permission for adding an object to repository database ./objects
remote: fatal: failed to write object
error: unpack failed: unpack-objects abnormal exit
To git@127.0.0.1:/srv/git-server/checkpoint.git
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'git@127.0.0.1:/srv/git-server/checkpoint.git'

Google 上也没找到办法,最终发现自己在初始化仓库的时候犯了一个错误。
创建完仓库需要变更所有者,使用命令漏掉了参数 `-R`,导致目录下面的文件没有变更到所有者:

sudo chown -R git:git repositoryname.git

使用 tf.train.Saver 中断和恢复 Tensorflow 的训练数据

'''
Save and Restore a model using TensorFlow.
This example is using the MNIST database of handwritten digits
(http://yann.lecun.com/exdb/mnist/)
 
Author: Aymeric Damien
Project: https://github.com/aymericdamien/TensorFlow-Examples/
'''
 
from __future__ import print_function
 
# Import MNIST data
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
 
import tensorflow as tf
 
# Parameters
learning_rate = 0.001
batch_size = 100
display_step = 1
model_path = "/tmp/model.ckpt"
 
# Network Parameters
n_hidden_1 = 256 # 1st layer number of features
n_hidden_2 = 256 # 2nd layer number of features
n_input = 784 # MNIST data input (img shape: 28*28)
n_classes = 10 # MNIST total classes (0-9 digits)
 
# tf Graph input
x = tf.placeholder("float", [None, n_input])
y = tf.placeholder("float", [None, n_classes])
 
 
# Create model
def multilayer_perceptron(x, weights, biases):
    # Hidden layer with RELU activation
    layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
    layer_1 = tf.nn.relu(layer_1)
    # Hidden layer with RELU activation
    layer_2 = tf.add(tf.matmul(layer_1, weights['h2']), biases['b2'])
    layer_2 = tf.nn.relu(layer_2)
    # Output layer with linear activation
    out_layer = tf.matmul(layer_2, weights['out']) + biases['out']
    return out_layer
 
# Store layers weight & bias
weights = {
    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),
    'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_hidden_2, n_classes]))
}
biases = {
    'b1': tf.Variable(tf.random_normal([n_hidden_1])),
    'b2': tf.Variable(tf.random_normal([n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_classes]))
}
 
# Construct model
pred = multilayer_perceptron(x, weights, biases)
 
# Define loss and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
 
# Initializing the variables
init = tf.global_variables_initializer()
 
# 'Saver' op to save and restore all the variables
saver = tf.train.Saver()
 
# Running first session
print("Starting 1st session...")
with tf.Session() as sess:
    # Initialize variables
    sess.run(init)
 
    # Training cycle
    for epoch in range(3):
        avg_cost = 0.
        total_batch = int(mnist.train.num_examples/batch_size)
        # Loop over all batches
        for i in range(total_batch):
            batch_x, batch_y = mnist.train.next_batch(batch_size)
            # Run optimization op (backprop) and cost op (to get loss value)
            _, c = sess.run([optimizer, cost], feed_dict={x: batch_x,
                                                          y: batch_y})
            # Compute average loss
            avg_cost += c / total_batch
        # Display logs per epoch step
        if epoch % display_step == 0:
            print("Epoch:", '%04d' % (epoch+1), "cost=", \
                "{:.9f}".format(avg_cost))
    print("First Optimization Finished!")
 
    # Test model
    correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
    # Calculate accuracy
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    print("Accuracy:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))
 
    # Save model weights to disk
    save_path = saver.save(sess, model_path)
    print("Model saved in file: %s" % save_path)
 
# Running a new session
print("Starting 2nd session...")
with tf.Session() as sess:
    # Initialize variables
    sess.run(init)
 
    # Restore model weights from previously saved model
    saver.restore(sess, model_path)
    print("Model restored from file: %s" % save_path)
 
    # Resume training
    for epoch in range(7):
        avg_cost = 0.
        total_batch = int(mnist.train.num_examples / batch_size)
        # Loop over all batches
        for i in range(total_batch):
            batch_x, batch_y = mnist.train.next_batch(batch_size)
            # Run optimization op (backprop) and cost op (to get loss value)
            _, c = sess.run([optimizer, cost], feed_dict={x: batch_x,
                                                          y: batch_y})
            # Compute average loss
            avg_cost += c / total_batch
        # Display logs per epoch step
        if epoch % display_step == 0:
            print("Epoch:", '%04d' % (epoch + 1), "cost=", \
                "{:.9f}".format(avg_cost))
    print("Second Optimization Finished!")
 
    # Test model
    correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
    # Calculate accuracy
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    print("Accuracy:", accuracy.eval(
        {x: mnist.test.images, y: mnist.test.labels}))

Vyprvpn 自动重连及升级后 tomato 路由器无法使用的解决办法

Tomato 路由器版的 Vyprvpn 升级后 installer.sh 和安装文件的下载链接都变成了 https, 导致无法下载和安装。

解决办法是:

直接下载 Vyprvpn 的安装文件。

可以在 install.sh 中找到安装文件的下载链接:

echo -n "Installing VyprVPN Router App...";

nvram set script_init="eval \`nvram get vypr_bootstrap\`";

nvram set vypr_bootstrap="
/bin/touch /tmp/vyprvpn_lock.\$\$;
/bin/mv -n /tmp/vyprvpn_lock.\$\$ /tmp/vyprvpn_lock;
if [ -f /tmp/vyprvpn_lock.\$\$ ];
then
 rm /tmp/vyprvpn_lock.\$\$;
else

 status=\"downloading\";
 /bin/kill -SIGTERM \"\$(pidof watchdog.sh)\" 2>/dev/null;
 echo \"{\\\"res\\\":\\\"OK\\\",\\\"data\\\":{\\\"status\\\":\\\"\$status\\\"}}\" > /www/user/vyprvpn_app_status.html;

 cd /tmp/var;
 /bin/rm -f vyprvpn.tar.gz;
 while [ ! -f vyprvpn.tar.gz ];
 do
 wget -O vyprvpn.tar.gz http://router-app.goldenfrog.netdna-cdn.com/tomato/mipsel/vyprvpn.tar.gz;
 sleep 5;
 done;

 /bin/kill -SIGTERM \"\$(pidof vyprvpn)\" 2>/dev/null;
 seconds=0;
 while [ \"\$(pidof vyprvpn)\" ];
 do
 sleep 1;
 seconds=\$((seconds+1));
 if [ \$seconds = 10 ];
 then
 /bin/kill -9 \"\$(pidof vyprvpn)\" 2>/dev/null;
 fi;
 if [ \$seconds = 15 ];
 then
 break;
 fi;
 done;

 /bin/kill -SIGTERM \"\$(pidof openvpn)\" 2>/dev/null;
 /bin/kill -SIGTERM \"\$(pidof pppd)\" 2>/dev/null;

 /bin/rm -rf /tmp/var/vyprvpn;
 /bin/tar -zxvf vyprvpn.tar.gz;
 /bin/rm -f vyprvpn.tar.gz;

 vyprvpn/scripts/run_vypr.sh;

 rm /tmp/vyprvpn_lock;
fi
";

nvram commit >/dev/null 2>&1;

eval `nvram get vypr_bootstrap` >/dev/null 2>&1;

sleep 3;

if [ "$(pidof vyprvpn)" ]; then
 echo " installation successful - please refresh your browser to use the VyprVPN Router App.";
else
 echo " installation failed.";
fi

下载链接:

http://router-app.goldenfrog.netdna-cdn.com/tomat o/mipsel/vyprvpn.tar.gz;

下载好后,解压,拷到 U 盘上(省略了细节,不明白可以留言)。

然后将下面的代码拷贝到路由器的`系统管理->脚本设置->初始化`里面,问号部分分别为路由器的用户名、密码和地址。

#!/bin/sh
# connecting information
ADMIN_USERNAME="????"
ADMIN_PASSWORD="????"
ROUTER_IP_ADDRESS="????"

sleep 3

# prepare vyprvpn
# cd /tmp/var/
cp -Rf /tmp/mnt/sda1/vyprvpn /tmp/var/

# delete google fonts
sed -i "s/<link rel=\"stylesheet\" href=\"\/\/fonts.googleapis.com\/css?family=Open+Sans:300,400,700\">//g" `grep googleapis -rl /tmp/var` >/dev/null 2>&1

# run vyprvpn
/tmp/var/vyprvpn/scripts/run_vypr.sh >/dev/null 2>&1 &

然后将以下代码拷贝到`系统管理->脚本设置->当WAN连机`

#!/bin/sh
# seconds between checks
WATCHDOG_SLEEP_SEC=90
# hostname or IP to ping
WATCHDOG_SITE="facebook.com"
# connecting information
ADMIN_USERNAME="????"
ADMIN_PASSWORD="????"
VYPR_USERNAME="????"
VYPR_PASSWORD="????"
ROUTER_IP_ADDRESS="????"

get_server()
{
 case $1 in
 0)
 echo "Macao"
 ;;
 1)
 echo "Japan"
 ;;
 2)
 echo "Taiwan"
 ;;
 3)
 echo "South Korea"
 ;;
 4)
 echo "Hong Kong"
 ;;
 5)
 echo "Singapore"
 ;;
 6)
 echo "Vietnam"
 ;;
 7)
 echo "Thailand"
 ;;
 8)
 echo "Philippines"
 ;;
 9)
 echo "Indonesia"
 ;;
 10)
 echo "Malaysia"
 ;;
 11)
 echo "Maldives"
 ;;
 12)
 echo "Marshall Islands"
 ;;
 13)
 echo "Australia - Perth"
 ;;
 14)
 echo "France"
 ;;
 15)
 echo "Germany"
 ;;
 *)
 echo "Macao"
 ;;
 esac
}

sleep 10

#logout
eval `wget -q -O - "http://${ADMIN_USERNAME}:${ADMIN_PASSWORD}@${ROUTER_IP_ADDRESS}/user/cgi-bin/vyprvpn.cgi?[%22VYPRVPN_LOGOUT%22]" >/dev/null 2>&1`

sleep 10

# login
eval `wget -q -O - "http://${ADMIN_USERNAME}:${ADMIN_PASSWORD}@${ROUTER_IP_ADDRESS}/user/cgi-bin/vyprvpn.cgi?[%22VYPRVPN_LOGIN%22,%22${VYPR_USERNAME}%22,%22${VYPR_PASSWORD}%22]" >/dev/null 2>&1`

counter=2
count_failure=0
while sleep $WATCHDOG_SLEEP_SEC
do
 SERVER_TO_CONNECT_TO=`get_server $((${count_failure}%16))`
 if ping -c 1 $WATCHDOG_SITE > /tmp/null
 then
 logger "VPN WATCHDOG CONNECTION PING SUCCESS"
 counter=0
 count_failure=0
 else
 logger "VPN WATCHDOG CONNECTION PING FAILED"
 sleep 5
 if [ ${counter} -eq 5 ]
 then
 eval `wget -q -O - "http://${ADMIN_USERNAME}:${ADMIN_PASSWORD}@${ROUTER_IP_ADDRESS}/user/cgi-bin/vyprvpn.cgi?[%22VYPRVPN_DISCONNECT%22]" >/dev/null 2>&1`
 sleep 10
 eval `wget -q -O - "http://${ADMIN_USERNAME}:${ADMIN_PASSWORD}@${ROUTER_IP_ADDRESS}/user/cgi-bin/vyprvpn.cgi?[%22VYPRVPN_LOGOUT%22]" >/dev/null 2>&1`
 sleep 10
 eval `wget -q -O - "http://${ADMIN_USERNAME}:${ADMIN_PASSWORD}@${ROUTER_IP_ADDRESS}/user/cgi-bin/vyprvpn.cgi?[%22VYPRVPN_LOGIN%22,%22${VYPR_USERNAME}%22,%22${VYPR_PASSWORD}%22]" >/dev/null 2>&1`
 sleep 10
 counter=0
 fi
 if ! ping -c 1 $WATCHDOG_SITE > /tmp/null
 then
 logger "VPN WATCHDOG CONNECTION - RECONNECTING"
 eval `wget -q -O - "http://${ADMIN_USERNAME}:${ADMIN_PASSWORD}@${ROUTER_IP_ADDRESS}/user/cgi-bin/vyprvpn.cgi?[%22VYPRVPN_CONNECT%22,%22${SERVER_TO_CONNECT_TO}%22,%22Chameleon%22]" >/dev/null 2>&1`
 fi
 counter=$((${counter}+1))
 count_failure=$((${count_failure}+1))
 fi
done 2>&1 &

Permission denied (publickey).

A problem occurred while I `git push` to my git server on ec2.

I handled this by following this three guide of which their original links are:

http://stackoverflow.com/questions/13363553/git-error-host-key-verification-failed-when-connecting-to-remote-repository

https://chenhuachao.com/2016/05/26/ssh%E5%87%BA%E9%94%99-sign-and-send-pubkey-signing-failed-agent-refused-operation/

Sorry for missing out the second source link, I will add that later.

Firstly, check your url if it’s right. If it’s outdated, update it with:

git remote set-url origin git://new.url.here

 

sign_and_send_pubkey: signing failed: agent refused operation
Permission denied (publickey).
fatal: Could not read from remote repository.

  1. mkdir ~/.ssh
  2. vim known_hosts - if you already have known_hosts, skip this.
  3. ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
  4. ssh-keygen -t rsa -C "user.email"
  5. Add the id_rsa.pub key to SSH keys list on your GitHub profile.

Set up your client

  1. Generate your key
    • ssh-keygen
  2. Configure ssh to use the key
    • vim ~/.ssh/config
  3. Copy your key to your server
    • ssh-copy-id -i /path/to/key.pub SERVERNAME

Your config file from step 2 should have something similar to the following:

Host SERVERNAME
Hostname ip-or-domain-of-server
User USERNAME
PubKeyAuthentication yes
IdentityFile ./path/to/key

eval “$(ssh-agent -s)”
ssh-add

ubuntu ftp server

Reference link:

http://www.krizna.com/ubuntu/setup-ftp-server-on-ubuntu-14-04-vsftpd/

FTP is used to transfer files from one host to another over TCP network. This article explains how to setup FTP server on ubuntu 14.04 .
There are 3 popular FTP server packages available PureFTPD, VsFTPD and ProFTPD. Here i’ve used VsFTPD which is lightweight and less Vulnerability.

Setup FTP server on Ubuntu 14.04

Step 1 » Update repositories .
krizna@leela:~$ sudo apt-get update
Step 2 » Install VsFTPD package using the below command.
krizna@leela:~$ sudo apt-get install vsftpd
Step 3 » After installation open /etc/vsftpd.conf file and make changes as follows.
Uncomment the below lines (line no:29 and 33).
write_enable=YES
local_umask=022
» Uncomment the below line (line no: 120 ) to prevent access to the other folders outside the Home directory.
chroot_local_user=YESand add the following line at the end.
allow_writeable_chroot=YES» Add the following lines to enable passive mode.
pasv_enable=Yes
pasv_min_port=40000
pasv_max_port=40100

Step 4 » Restart vsftpd service using the below command.
krizna@leela:~$ sudo service vsftpd restart
Step 5 » Now ftp server will listen on port 21. Create user with the below command.Use /usr/sbin/nologin shell to prevent access to the bash shell for the ftp users .
krizna@leela:~$ sudo useradd -m john -s /usr/sbin/nologin
krizna@leela:~$ sudo passwd john

Step 6 » Allow login access for nologin shell . Open /etc/shells and add the following line at the end.
/usr/sbin/nologin
Now try to connect this ftp server with the username on port 21 using winscp orfilezilla client and make sure that user cannot access the other folders outside the home directory.
setup FTP server ubuntu 14.04
Please note using ftp on port 21 is a big security risk . it’s highly recommended to use SFTP. Please continue for SFTP configuration

Secure FTP ( SFTP )

SFTP is called as “Secure FTP” which generally use SSH File Transfer Protocol . so we need openssh-server package installed , Issue the below command if it’s not already installed.
krizna@leela:~$ sudo apt-get install openssh-server
Step 7 » Create a new group ftpaccess for FTP users.
krizna@leela:~$ sudo groupadd ftpaccess
Step 8 » Now make changes in this /etc/ssh/sshd_config file.
» Find and comment the below line
Subsystem sftp /usr/lib/openssh/sftp-serverand Add these lines at the end of the file.
Subsystem sftp internal-sftp
Match group ftpaccess
ChrootDirectory %h
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp

Step 9 » Restart sshd service.
krizna@leela:~$ sudo service ssh restart
Step 10 » The below steps must be followed while creating Users for sftp access.
Create user john with ftpaccess group and /usr/bin/nologin shell.
krizna@leela:~$ sudo useradd -m john -g ftpaccess -s /usr/sbin/nologin
krizna@leela:~$ sudo passwd john
Change ownership for the home directory.
krizna@leela:~$ sudo chown root /home/johnCreate a folder inside home directory for writing and change ownership of that folder.
krizna@leela:~$ sudo mkdir /home/john/www
krizna@leela:~$ sudo chown john:ftpaccess /home/john/www

Now try to connect server using SFTP ( port : 22 ) and makesure Users can upload files to www directory and cannot access other folders outside home directory.setup FTP server ubuntu 14.04
If you want use both FTP and SFTP together, please perform above steps ( Step 10 ) while creating users . For existing users, move them to ftpaccess group and create folder structure and ownership changes as below.
krizna@leela:~$ sudo usermod john -g ftpaccess -s /usr/sbin/nologin
krizna@leela:~$ sudo chown root /home/john
krizna@leela:~$ sudo mkdir /home/john/www
krizna@leela:~$ sudo chown john:ftpaccess /home/john/www

Now john can able to upload files to www folder using FTP as well as SFTP.

WebRTC – Video Tag Not Working In Chrome

Google 浏览器 WebRTC 的 getUserMeida 在本地工作正常,但上传到服务期访问,发现 Video 标签没有视频输入,F12 查看前端报错:

getUserMedia() no longer works on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.

最新版的 Chrome 浏览器需要 https 访问才能调用 getUserMedia。

解决办法是购买https证书,或者自制证书让服务器支持 https 访问。

免费申请的网站:

https://startssl.com/

https://letsencrypt.org

Python Beautiful Soup gb2312 Windows-1252 乱码问题

当初,Python 的编码把我折磨得死去活来,一直准备写一篇文章总结一下。先把我看到的两篇对我最有用的文章贴出来。然后再来慢慢修改整理。
文章1:
Beautiful Soup gb2312乱码问题

http://groups.google.com/group/python-cn/browse_thread/thread/cb418ce811563524

 请注意 gb2312 不是 “gb2312”,凡 gb2312 的请换成 gb18030.
微软将 gb2312 和 gbk 映射为 gb18030,方便了一些人,也迷惑了一些人。

即,实际上该网页是GB18030的编码,所以按照这里:

上午解决了网页解析乱码的问题

http://blog.csdn.net/fanfan19881119/article/details/6789366

(原始出处为:http://leeon.me/a/beautifulsoup-chinese-page-resolve

的方法,传递GB18030给fromEncoding,才可以:

 page = urllib2.build_opener().open(req).read()
soup = BeautifulSoup(page, fromEncoding=”GB18030“)

   而其中,也解释了,为何HTML标称的GBK的编码,但是却解析出来为windows-1252了:

 最近需要写一个python的RSS抓取解析程序,使用了feed parser。但是对于百度新闻的RSS,其编码方式为gb2312,feed parser探测出来的编码却是windows-1252,结果中文内容都是一堆乱码。问题在于,并不是feedparser不能识别出gb2312编码,而是国人们往往将gb2312与gbk编码等同,某些已经使用了gbk编码里的字符的,仍然声称内容为gb2312编码。feedparser对gb2312编码严格遵循gb2312字符集范围,当探测到超出这一范围的字符,便将编码回退到windows-1252。由于百度的RSS实际使用的应该是gbk编码,里面含有超出gb2312范围的字符,于是feedparser便擅自决定了将编码退回windows-1252,导致了中文乱码的现象。

 

文章2:

【整理】Python中实际上已经得到了正确的Unicode或某种编码的字符,但是看起来或打印出来却是乱码

http://www.crifan.com/python_already_got_correct_encoding_string_but_seems_print_messy_code/

 

(Solved)How to break the loop “Restart Surface to Modify security settings”

Handing on my new Surface Pro 4,I try to  install ubuntu on it. But I lost my “Security” menu in UEFI while I try to boot from a PE in my USB stick.Then I get stuck in the “Restart to Surface UEFI” loop with a message ‘The security settings on Surface cannot be modified at this time. A restart is required to make changes to the security settings’. The default security settings menu no longer appear no matter how many times I restart. I googled as many as I can, but I still cannot find a way to fix this.

1

Though I nearly give up this, but as a geek I have to know what’s the ball in it. It still lingered in my mind luring me. And most important I feel I lost my control on my computer, which is unacceptable!

I have to know!!! Or I can’t stop to ponder this.

Last night, an idea occured in my mind. I try to turn off the ‘Devices’ to trigger the settings to fix this. The result is amazing. I didn’t believe it worked. The pity is I still don’t know the reason why this happend.

Turn off the Devices:

2

The Security settings come back again:

3

Turn on all the Devices, you don’t expect a computer without camera, WIFI, and bluetooth…

4

Enjoy your full-controled computer again!

—-

by Chen Miao

python中函数参数传递的几种方法

python中函数参数传递的几种方法

Python中函数参数的传递是通过“赋值”来传递的。但这条规则只回答了函数参数传递的“战略问题”,并没有回答“战术问题”,也就说没有回答怎么赋值的问题。函数参数的使用可以分为两个方面,一是函数参数如何定义,二是函数在调用时的参数如何解析的。而后者又是由前者决定的。函数参数的定义有四种形式:

   1. F(arg1,arg2,…)
   2. F(arg2=<value>,arg3=<value>…)
   3. F(*arg1)
   4. F(**arg1)

第1 种方式是最“传统”的方式:一个函数可以定义不限个数参数,参数(形式参数)放在跟在函数名后面的小括号中,各个参数之间以逗号隔开。用这种方式定义的函数在调用的时候也必须在函数名后的小括号中提供相等个数的值(实际参数),不能多也不能少,而且顺序还必须相同。也就是说形参和实参的个数必须一致,而且想给形参1的值必须是实参中的第一位,形参与实参之间是一一对应的关系,即“形参1=实参1 形参2=实参2…”。很明显这是一种非常不灵活的形式。比如:

def addOn(x,y): return x + y

这里定义的函数addOn,可以用addOn(1,2)的形式调用,意味着形参x将取值1,主将取值2。addOn(1,2,3)和addOn (1)都是错误的形式。
第2种方式比第1种方式好一点,在定义的时候已经给各个形参定义了默认值。因此,在调用这种函数时,如果没有给对应的形式参数传递实参,那么这个形参就将使用默认值。比如:

def addOn(x=3,y=5): return x + y”

那么addOn(6,5)的调用形式表示形参x取值6,y取值5。此外,addOn(7)这个形式也是可以的,表示形参x取值7,y取默认值5。这时候会出现一个问题,如果想让x取默认值,用实参给y赋值怎么办?前面两种调用形式明显就不行了,这时就要用到Python中函数调用方法的另一大绝招 ──关健字赋值法。可以用addOn(y=6),这时表示x取默认值3,而y取值6。这种方式通过指定形式参数可以实现可以对形式参数进行“精确攻击”,一个副带的功能是可以不必遵守形式参数的前后顺序,比如:addOn(y=4,x=6),这也是可以的。这种通过形式参数进行定点赋值的方式对于用第1种方式定义的函数也是适用的。
上面两种方式定义的形式参数的个数都是固定的,比如定义函数的时候如果定义了5个形参,那么在调用的时候最多也只能给它传递5个实参。但是在实际编程中并不能总是确定一个函数会有多少个参数。第3种方式就是用来应对这种情况的。它以一个*加上形参名的方式表示,这个函数实际参数是不一定的,可以是零个,也可以是N个。不管是多少个,在函数内部都被存放在以形参名为标识符的tuple中。比如:
对这个函数的调用addOn() addOn(2) addOn(3,4,5,6)等等都是可以的。

与第3种方式类似,形参名前面加了两个*表示,参数在函数内部将被存放在以形式名为标识符的dictionary中。这时候调用函数必须采用key1=value1、key2=value2…的形式。比如:

   1. def addOn(**arg):
   2.     sum = 0
   3.     if len(arg) == 0: return 0
   4.     else:
   5.        for x in arg.itervalues():
   6.           sum += x
   7.     return sum

那么对这个函数的调用可以用addOn()或诸如addOn(x=4,y=5,k=6)等的方式调用。

上面说了四种函数形式定义的方式以及他们的调用方式,是分开说的,其实这四种方式可以组合在一起形成复杂多样的形参定义形式。在定义或调用这种函数时,要遵循以下规则:

   1. arg=<value>必须在arg后
   2. *arg必须在arg=<value>后
   3. **arg必须在*arg后

在函数调用过程中,形参赋值的过程是这样的:
首先按顺序把“arg”这种形式的实参给对应的形参
第二,把“arg=<value>”这种形式的实参赋值给形式
第三,把多出来的“arg”这种形式的实参组成一个tuple给带一个星号的形参
第四,把多出来的“key=value”这种形式的实参转为一个dictionary给带两个星号的形参。
听起来好复杂,实际是是很简单的。很直观,来看例子:

   1. def test(x,y=5,*a,**b):
   2. print x,y,a,b

就这么一个简单函数,来看看下面对这个函数调用会产生什么结果:
test(1) ===> 1 5 () {}
test(1,2) ===> 1 2 () {}
test(1,2,3)  ===> 1 2 (3,) {}
test(1,2,3,4) ===> 1 2 (3,4)
test(x=1)   ===> 1 5 () {}
test(x=1,y=1)  ===> 1 1 () {}
test(x=1,y=1,a=1)   ===> 1 1 () {‘a’:1}
test(x=1,y=1,a=1,b=1)   ===> 1 1 () {‘a’:1,’b’:1}
test(1,y=1) ===> 1 1 () {}
test(1,2,y=1) ===> 出错,说y给赋了多个值
test(1,2,3,4,a=1) ===> 1 2 (3,4) {‘a’:1}