您是否曾经以为有一天您太快地进入了PHP Web编程?
已经过去了数年,您已经获得了很多经验,除了PHP之外,别无选择。 也许,您有时会怀疑自己所做的选择,但无法在此时此刻证实您的疑问。 同时,您需要真实的例子。 您想了解在工作的某些方面可能发生的变化。
今天,我将尝试回答以下问题:“
如果我们使用Python而不是PHP怎么办? ”。
我已经多次问过这个问题。 我已经使用PHP 11年了,并且是一位认证的PHP专家。 我已经掌握了它,因此它可以按照我想要的方式工作。 令我感到非常困惑的是,有几篇文章严厉批评了PHP(
PHP:糟糕的设计形式 )。 但是,当机会来临时,我改用Ruby,然后改用Python。 最终,我选择了后者。 现在,我将尝试解释我们这些Python家伙如何生活在这里。

文章格式
学习一种新语言的最好方法是将其与您已经可以使用的一种语言进行比较,除非新语言与当前语言有很大不同。 Ruby Web门户上的文章(
其他语言的Ruby )提供了这样的比较,但是缺少示例。
我还应该注意,本文仅比较在切换到新语言后的最初几周引起您注意的方面。
准备控制台
我已尽力使本文具有交互性。 因此,建议阅读本文时在控制台中运行所有示例。 您将需要一个PHP控制台,或者可以使用
PsySH控制台,甚至更好:
php -a
还有一个Python控制台。 我建议使用
bpython或
ipython ,因为它们已经将代码完成功能与该语言中集成的默认控制台进行了比较。 但是,以下选项也适用:
python
然后:
import rlcompleter import readline readline.parse_and_bind("tab: complete")
避免重复这些动作使用以下命令创建〜/ .pyrc文件:
import rlcompleter import readline readline.parse_and_bind("tab: complete")
在〜/ .bashrc文件中添加几行:
export PYTHONSTARTUP="${HOME}/.pyrc" export PYTHONIOENCODING="UTF-8"
Adn无需立即登录即可立即进行更改:
source ~/.bashrc
关于语言
- Python是一种语言,具有很强的鸭子动态键入功能( 请参阅有关键入的信息 )。 Python在应用方面不受限制。 它用于Web开发,守护程序,科学计算或用作扩展语言。 就输入而言,类似的语言:Ruby。
- PHP是一种具有弱鸭动态输入的语言。 PHP也是一种通用语言,但是它的应用领域主要涉及Web和守护程序。 其他功能无法正确解决,使其无法在生产中使用。 有些人认为PHP是注定要死的 。 在键入方面类似的语言:JavaScript,Lua,Perl。
一般细节
- 无论Python版本如何,代码均以.py文件编写。 因为Python最初是作为通用编程语言开发的,所以不需要像<?PHP这样的开头标签。
- 此外,出于相同原因,没有php.ini。 有两打
环境变量 ,但是在大多数情况下(除PYTHONIOENCODING之外)它们是未定义的。 换句话说,对于大多数通用语言而言,没有默认的连接到基础,错误过滤器管理,限制管理,扩展等。 因此,程序在大多数情况下的行为类似(它们的行为不取决于团队负责人的喜好设置)。 在大多数情况下,诸如php.ini之类的设置都存储在应用程序的主配置文件中。 - 字符串的末尾不需要分号。 但是,如果我们在其中放置分号,则其工作方式类似于PHP。 但是,这是不必要的也是不希望的,因此您可以简单地将其忘记。
- 变量不能以$开头(PHP是从Perl继承而又采用了Perl的)
来自Bash)。 - 周期和条件下的分配不适用,因此没有人对分配进行错误比较,这是一个常见错误(如语言作者所相信的)。 如果需要,请参阅PEP 572 for python 3.8。
- 解析文件后,Python会自动将扩展名为.pyc的文件副本(假定您的Python版本低于3.3,并且尚未安装PYTHONDONTWRITEBYTECODE )放入字节码所在的文件夹中。 然后,它将始终执行此文件,除非您更改源。
这些文件在所有IDE中都会被自动忽略,并且通常不会产生干扰。 考虑到.pyc文件很可能位于文件缓存中,因此可以将此功能视为PHP APC的完全类似产品。 - 代替NULL,TRUE,false,我们应该使用None,True,false(在这种情况下尤其如此)。
嵌套和缩进
这是不寻常的事情:代码嵌套是由缩进而不是方括号确定的。
因此,代替:
foreach($a as $value) { $formatted = $value.'%'; echo $formatted; }
我们应该写以下内容:
for value in a: formatted = value + '%' print(formatted)
等等,等等! 不要关闭文章。 在这里,您可能会犯我犯的错误。
曾经,我认为使用缩进进行代码嵌套的想法很荒谬。 我的整个天性都在抗议它,因为所有开发人员都以自己的方式编写代码,无论使用何种样式指南。
这是世界的奥秘:没有缩进问题。 在大多数情况下(占案例的99%),缩进由IDE像其他任何语言一样自动放置。 您只是根本不考虑它。 在使用该语言的两年中,我没有遇到任何与缩进有关的问题。
强大的打字
接下来要注意的是“强类型”。 但是,首先需要一些代码:
print '0.60' * 5; print '5' == 5; $a = array('5'=>true); print $a[5]; $value = 75; print $value.'%'; $a='0'; if($a) print 'non zero length';
上面的所有示例都可以归功于动态键入。
是的,我知道Type声明可用于PHP。 但是默认情况下未启用该功能,因此它不适用于任何地方。
但是,以下内容在Python中不起作用:
>>> print "25" + 5 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: cannot concatenate 'str' and 'int' objects
通常,数据类型不会混入您的代码中,并且这种效果不会分散您的注意力。 总的来说,当我使用PHP进行编码时,每个项目只有少数情况可以有效地使用动态类型。 在所有其他情况下,相同类型的变量彼此交互。
强类型键入会影响错误处理。 例如,如果一个
int函数返回一个整数,则它不能将
None返回到字符串,该类型不能从中显式提取。 在这种情况下,将引发异常。 可能需要将所有用户数据转换为所需的数据类型,否则有一天将在生产版本中引发异常。
try: custom_price = int(request.GET.get('custom_price', 0)) except ValueError: custom_price = 0
它不仅影响标准函数,而且还影响列表,字符串的某些方法以及其他库中的某些函数。 通常,Python开发人员会记住所有可能引发的异常,并加以考虑。 如果开发人员不记得他们,他们将检查库代码。 当然,有时不会考虑所有情况,并且用户可能会在生产版本中引起异常。 由于这是一种罕见的现象,通常Web框架会自动将它们发送到管理员的邮件中,因此这种情况会很快得到解决。
为了在单个表达式中使用各种数据类型的值,应该对其进行转换。 有一些功能:
str ,
int ,
bool ,
long 。 此外,还有更方便的格式化决策。
弦乐
格式化
在PHP中:
$this_way = 'this_way'; echo "Currently you do it $this_way or {$this way}."; echo "Or ".$this_way."."; echo sprintf("However the following is possible: , %s or %1$'.9s.", $this_way);
现在,您应该学习以其他方式做到这一点:
etot = 'this' var = 'option' print('To %s option' % etot) print(etot + ' option can also be used, but not recommended) print('Or to %s %s' % (etot, var)) print('Or to %(etot)s %(var)s' % {'etot': etot, 'var': var}) # Very useful for localization team print('Or to {} {}'.format(etot, var)) print('Or to {1} {0}'.format(var, etot)) print('Or to {etot} {var}'.format(var=var, etot=etot)) # And finally print(f'Or to {etot} {var}') # Starting from Python 3.6
有更多选项,本地化还有一个方便的选项。
字符串方法
Python在PHP中缺少一些东西:内置方法。 让我们比较一下:
strpos($a, 'tr'); trim($a);
与 a.index('tr') a.strip()
您多久做一次这样的事情?
substr($a, strpos($a, 'name: '));
与 a[a.index('name: '):]
Unicode支持
最后是Unicode。 在Python 2中,默认情况下,所有字符串都不是Unicode。 (在Python 3中,默认情况下所有字符串均为Unicode)。 但是,当您在字符串的开头添加字符
u时,它会自动变为Unicode。 然后,Python的所有内置(而非内置)字符串方法都将正常运行。
>>> len(' ')

在PHP中,自然的Unicode处理正在为PHP 6开发,但PHP 6被取消了( Andrei Zmievski:Wat发生在Unicode和PHP 6上 )。
顺便说一下,在PHP中,您可以使用MBString函数重载来获得类似的效果,但已弃用。
但是,您将无法使用重载函数使用二进制字符串,但仍将字符串作为数组使用。
关于原始字符串(可选)原始字符串
您应该知道单引号字符串和双引号字符串之间的区别:
$a = 'Hello.\n'; $a[strlen($a)-1] != "\n";
Python中的类似功能称为原始字符串。 要使用它,请将字符
r放在单引号字符串之前。
a = r'Hello.\n' a[-1] != '\n'
数组
现在是该阵列的时候了。 在PHP中,您可以使用整数或字符串作为键:
var_dump([0=>1, 'key'=>'value']);

在PHP中,数组不是标准数组( list ),而是关联数组( dictionary )。 标准数组在PHP中也可用,它们是SPLFixedArray 。 它们需要较少的内存,可能会更快地工作,但是由于创建和扩展的复杂性,很少使用。
在Python中,数组使用四种数据类型:
- 清单
a = [1, 2, 3]
- 字典-字典。 字典没有存储数据的顺序(就像在PHP中一样)。
d = {'a': 1, 'b': 2, 'c': 3}
- 元组。 像非齐次值的固定数组之类的东西。 非常适合从函数返回多个值并紧凑地存储配置。
t = (True, 'OK', 200, )
- 设置。 基本上,这是没有存储顺序的唯一值的列表。
s = set([1,3,4]) s[0] = False
在PHP中,数组有点像瑞士军刀,它们可以满足所有目的。 对于Python,您需要使用计算机科学的本机数据数组。 此外,您需要为每种情况使用适当的数据数组。 您可能会说,这些是程序员不应该面对的不必要的困难。 好吧,这不是重点。
- 首先:在元组,集合,列表和字典之间进行选择的可能性不会使事情变得困难-它只是成为潜意识的习惯,如换档。
- 第二:在大多数情况下使用列表或字典。
- 第三:在大多数情况下,当您需要存储键值对时,顺序不是必需的,但是,在需要保留顺序时,在大多数情况下,只有值而不是键值对。
- 第四:Python有一个有序字典-OrderedDict 。
进口货
这是一个非常有趣的功能。 这是必须使用的名称空间的替代概念。
在PHP中,您编写了
require_once ,直到PHP执行会话结束之前,它一直可用。 通常,使用CMS时,开发人员会将所有内容放入类中,将它们放置在特殊的位置,编写一个知道这些位置的小函数,然后通过
spl_autoload_register在文件的开头注册该函数。
但是,在Python中,每个文件都有其自己的名称空间。 因此,文件将仅包含您导入到那里的对象。 默认情况下,仅标准Python库可用(大约80个函数)。
检查以下示例:
假设您已经创建了
tools / logic.py文件:
def is_prime(number): max_number = int(sqrt(number)) for multiplier in range(2, max_number + 1): if multiplier > max_number: break if number % multiplier == 0: return False return True
现在,您想在
main.py文件中使用它。 在这种情况下,您需要将整个文件或所需的文件实体导入到正在处理的目标文件中。
from tools.logic import is_prime print(is_prime(79))
该规则适用于整个Python。 在大多数情况下,当您开始处理任何文件时,首先需要将辅助Python对象导入您的文件:您自己的集成库。 就像mysqli_ *,pdo_ *,memcached_ *这样的PHP函数以及您的整个代码都存储在名称空间中,您必须将它们导入到您使用的每个文件中。 这种方法有什么优势?
- 第一:不同文件中的不同对象可以具有相同的名称。 但是,由您选择对象,其名称和目标文件。
- 第二:重构要容易得多。 您始终可以跟踪类,函数或任何其他实体。 使用简单的搜索即可找到功能,并查看在何处/如何使用它。
- 第三:此功能使开发人员(至少在某种程度上)考虑了代码结构。
另一方面,我们只能提到一个缺点-
循环进口 。 但是,这是一个罕见的问题。 此外,这是一个熟悉的问题,开发人员知道解决该问题的方法。
始终使用导入是否方便? 这取决于您的喜好。 如果您希望对代码有更多控制,则最好使用导入。 一些团队甚至制定了规范分配外部代码的顺序的规则,以最大程度地减少循环导入的数量。 如果您的团队没有这样的规则,并且您不想打扰很多,则只需依靠IDE即可自动导入您使用的所有内容。 另外:导入不是Python独有的功能,它们还用在Java和C#中。
到目前为止,还没有投诉。
函数中的参数* args和** kwargs
具有默认参数的语法通常是相同的:
function makeyogurt($flavour, $type = "acidophilus") { return "Making a bowl of $type $flavour."; }
与 def makeyogurt(flavour, ftype="acidophilus"): return "Making a bowl of %s %s." % (ftype, flavour, )
但是,有时您可能需要一个用于未知数量参数的函数。
例如,代理功能,记录功能或用于接收信号的功能。 在PHP中,从5.6版开始,可以使用以下语法:
function sum(...$numbers) { $acc = 0; foreach ($numbers as $n) { $acc += $n; } return $acc; } echo sum(1, 2, 3, 4);
分别在Python中,您可以将未命名的参数添加到数组中,并将命名的参数添加到字典中:
def acc(*args, **kwargs): total = 0 for n in args: total += n return total print(acc(1, 2, 3, 4))
* args-未命名参数列表,
** kwargs-命名参数字典。
班级
看下面的代码:
class BaseClass: def __init__(self): print("In BaseClass constructor") class SubClass(BaseClass): def __init__(self, value): super(SubClass, self).__init__()
与PHP的主要区别如下:
- 使用self代替$ this ,并且始终使用访问运算符(“。”)调用方法。 此外,“自我”应该始终是所有方法中的第一个参数(嗯,在大多数方法中)。 关键是Python为所有方法提供了带有第一个参数的对象链接(对象本身可以添加到任何名称的变量中)。
- 就像在PHP中一样,有一个魔术名称的类似物。 代替__construct-__ init__ 。 代替__get-__getattr__等。
- 不需要新的 。 创建类实例与调用函数相同。
- 对父方法的更复杂的调用。 至于超级,您始终需要牢记所有细节。 parent ::对于PHP来说,结构不那么庞大。
我们还应该提到以下内容:
- 可以继承多个类。
- 没有公共的 , 受保护的 , 私人的 。 Python允许通过简单的分配在运行时更改实例结构(以及整个类),因此无需保护。 因此,也不需要反射。 但是,有一个类似的受保护状态-名称前加双下划线。 但是,此操作只是将变量/方法的可见名称更改为_%ClassName%__%varname%,以允许使用隐藏数据。
- 没有静态的,最终的类和接口。 通常,该模型在Python中更基于对象。 您可能会拥有一个包含所有必需功能的文件,或者一个在导入时返回相同实例的文件,而不是Singleton。 除了接口之外,您可能会创建一个类,该类引发由于某种原因而未重新分配的方法的异常(即可能的解决方法)。
- 不需要仅应用面向对象的编程(OOP)。 由于无论如何一切都是对象(即使是布尔值),并且语法没有不同的运算符可用于从导入的文件中调用方法或函数,因此所有调用均由访问运算符(“。”)执行。 因此,封装不一定需要OOP。 因此,在大多数项目中,实际上是在需要的地方创建类。
编码风格
我参与了多个长期项目,并注意到所有团队成员都有不同的编码风格。 在许多情况下,代码可以帮助识别代码作者。 我一直希望采用任何代码样式标准来实现一致性。
但是,在团队内部批准此文档时,总是会有很多争论。 这个问题也影响Python,但程度较小,因为有资格的专家提出了几项建议,这些建议绝对足以开始:
此外,还有一个所谓的Python Zen。 它的一条规则规定:“以前应该有一种方法,最好只有一种。” 因此,不能以几种近似的方式编写代码。 当然,这是理想主义,但在许多情况下有帮助:
- 我们使用一个较小的方法集和其他集成库(例如,用于哈希总数)来代替包含几个相互部分重复的功能的大型库存库 。
- 我们始终使用len而不是strlen和count 。
等
Python版本
新版本的PHP始终与以前的版本向后兼容,尽管有时需要进行改进。 另一方面,有Python 2和Python 3,它们在默认情况下一点都不兼容。 但是,最近,Python开发人员已经大大改善了这种情况。 您可以为两个Python版本编写代码,但是如果您使用异步编程或Unicode新功能(UTF 8)等新的Python 3功能,则可能会遇到困难。 因此,已经开发和编码多年的项目仍使用Python 2。
但是对于新项目,没有理由使用Python 2。
跨语言别名
以下是关键字列表,这些关键字说明了Python为您当前使用的技术提供的替代方法。
- 作曲家->点子
- mod_php-> mod_wsgi
- nginx + php-fpm-> nginx + uwsgi + uwsgi_python
- daemon.io->龙卷风,扭曲
- Zend框架-> Django
- 猎鹰->猎鹰
结论
您怎么知道是否需要?
- 您认为打字越强越好。
- 您更喜欢具有组织良好的体系结构的语言。
- 你是一个完美主义者,过度的多样性会惹恼你。
- 您所在城市的Python职位看起来更有希望(或者您对仅开发Web门户感到无聊)。
- 您希望您的主要编程语言适合于开发任何类型的软件(考虑与动态类型相关的合理限制)。
- 您不喜欢初级开发人员的技能水平(由于学习曲线相对较低)。
我学习Python的方式
如果您是一位经验丰富的开发人员,则最多需要三周的时间来学习它,而无需付出太多努力。
- 第一周 :阅读Dive Into Python ,第2-7章。 您可以简要浏览其他章节,仅关注有趣的地方。 同时,用Project Euler完成10个任务。 最后,创建一个接受参数的控制台实用程序。 您可以移植任何以前的bash脚本,或者从BusyBox或其他新东西创建ls的类似物。 关键是脚本应该执行一些有用的事情,而您经常要做的事情。 例如,我已经移植了PHP实用程序 ,该实用程序可以在内存缓存中显示数据。
- 第二周 :在Django 中创建一个简单的Medium类似物,并在任何托管平台上使用gun。 注意组件:注册,登录,密码恢复,共享帖子和评论并删除它们,检查操作权限。
- 第三周 :选择您想工作的公司,将简历发送给他们,要求他们进行Python测试任务以测试您的技能。
祝你好运!