【问题标题】:Javascript to Python - Understanding how classes, methods and properties workJavascript to Python - 了解类、方法和属性的工作原理
【发布时间】:2015-02-24 05:24:19
【问题描述】:

在 Javascript 中,有多种方法可以实现方法的继承。 下面是一个使用几种方法的混合示例:

A = {
    name: 'first',
    wiggle: function() { return this.name + " is wiggling" },
    shake: function() { return this.name + " is shaking" }
}

B = Object.create(A)
B.name = 'second'
B.bop = function() { return this.name + ' is bopping' }


C = function(name) {
    obj = Object.create(B)
    obj.name = name
    obj.crunk = function() { return this.name + ' is crunking'}

    return obj
}

final = new C('third')

这给了我以下继承层次结构。

需要注意的重要事项之一是每个对象的name 属性。当运行一个方法时,即使是原型链的最底层,this 关键字定义的本地上下文确保使用 localmost 属性/变量。

我最近转向 Python,但我无法理解子类如何访问超类方法,以及变量范围/对象属性如何工作。

我在 Scrapy 中创建了一个 Spider(非常成功),它在单个域上抓取了 2000 多个页面并将它们解析为我需要的格式。许多助手只在主要的parse_response 方法中起作用,我可以直接在数据上使用它。原来的蜘蛛看起来像这样:

from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from spider_scrape.items import SpiderItems

class ScrapeSpider(CrawlSpider):

    name              =   "myspider"
    allowed_domains   =   ["domain.com.au"]
    start_urls        =   ['https://www.domain.com.au/']
    rules             =   (Rule(SgmlLinkExtractor(allow=()), 
                                                  callback="parse_items", 
                                                  follow=True), )

    def parse_items(self, response):
        ...

回调函数 parse_items 包含为我处理响应的逻辑。当我概括所有内容时,我得到了以下结果(打算在多个域上使用它):

#Base

class BaseSpider(CrawlSpider):
    """Base set of configuration rules and helper methods"""

    rules = (Rule(LinkExtractor(allow=()),
                                    callback="parse_response",
                                    follow=True),)

    def parse_response(self, response):
            ...

        def clean_urls(string):
          """remove absolute URL's from hrefs, if URL is form an external domain do nothing"""
          for domain in allowed_domains:
              string = string.replace('http://' + domain, '')
              string = string.replace('https://' + domain, '')
          if 'http' not in string:
              string = "/custom/files" + string
          return string


#Specific for each domain I want to crawl
class DomainSpider(BaseSpider):

    name = 'Domain'
    allowed_domains = ['Domain.org.au']
    start_urls      = ['http://www.Domain.org.au/'
                      ,'http://www.Domain.org.au/1']

当我通过 Scrapy 命令行运行它时,我在控制台中出现以下错误:

经过一些测试,将列表理解更改为此使其工作:for domain in self.allowed_domains:

一切都好,这似乎与 Javascript 中的 this 关键字非常相似——我正在使用对象的属性来获取值。还有更多的变量/属性可以保存抓取所需的 XPath 表达式:

class DomainSpider(BaseSpider):

    name = 'Domain'
    page_title      =      '//title'
    page_content    =      '//div[@class="main-content"]'

更改 Spider 的其他部分以模仿 allowed_domains 变量的部分,我收到此错误:

我尝试以几种不同的方式设置属性,包括使用 self.page_content 和/或 __init__(self) 构造函数,但没有成功但出现不同的错误。

我完全不知道这里发生了什么。我期望发生的行为是:

  1. 当我从终端运行 scrapy crawl <spider name> 时,它会实例化 DomainSpider 类
  2. 该类中的任何类常量都可用于其继承的所有方法,类似于 Javascript 及其 this 关键字
  3. 由于上下文,其超类中的任何类常量都会被忽略。

如果有人可以

  • 向我解释以上内容
  • 向我指出比 LPTHW 更丰富的东西,而不是 Python 的 TDD,这将是惊人的。

提前致谢。

【问题讨论】:

标签: python python-2.7 inheritance methods scrapy


【解决方案1】:

我不熟悉 JavaScript,但与您类似的问题总是包含一个答案,建议您必须学习在 Python 中执行此操作的方法,而不是试图强迫 Python 像您的其他语言。试图在 Python 中重新创建你的 Javascript 风格的风格,我想出了这个:

class A(object):
    def __init__(self):
        self.name = 'first'
    def wiggle(self):
        return self.name + ' is wiggling'
    def shake(self):
        return self.name + ' is shaking'

创建A的实例,更改其名称并为实例添加方法属性

b = A()
b.name = 'second'
b.bop = lambda : b.name + ' is bopping'

返回A 实例的函数,带有附加属性crunk。我不认为这对你的例子是正确的,thing 不会有 bop 方法,尽管函数中的另一个语句可以添加一个。

def c(name):
    thing = A()
    thing.name = name
    thing.crunk = lambda : thing.name + ' is crunking'
    return thing

final = c('third')

没有任何继承,只是 A 的实例和附加属性。你会得到以下结果:

>>> 
>>> b.name
'second'
>>> b.bop()
'second is bopping'
>>> b.shake()
'second is shaking'
>>> b.wiggle()
'second is wiggling'
>>> 
>>> final.name
'third'
>>> final.crunk()
'third is crunking'
>>> final.shake()
'third is shaking'
>>> final.wiggle()
'third is wiggling'
>>> final.bop()

Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    final.bop()
AttributeError: 'A' object has no attribute 'bop'
>>> 

在 Python 中你会这样做:

A 具有name 属性的默认参数和两个将绑定到A 实例的方法。 name 是一个instance 属性,因为它是在__init__ 中定义的。只有 instancesA 将具有 name 属性 - A.name 将引发 AttributeError。

class A(object):
    def __init__(self, name = 'first'):
        self.name = name
    def wiggle(self):
        return self.name + ' is wiggling'
    def shake(self):
        return self.name + ' is shaking'

Foo 继承自 A 的所有内容,并定义了一个附加属性 bop

class Foo(A):
    def bop(self):
        return self.name + ' is bopping'

Bar 继承自 Foo 的所有内容并定义了一个附加属性 crunk

class Bar(Foo):
    def crunk(self):
        return self.name + ' is crunking'

Baz 继承自 Bar 的所有内容并覆盖 wiggle

class Baz(Bar):
    def wiggle(self):
        return 'This Baz instance, ' + self.name + ', is wiggling'

foo = Foo('second')
bar = Bar('third')
baz = Baz('fourth')

用法:

>>> 
>>> foo.name
'second'
>>> foo.bop()
'second is bopping'
>>> foo.shake()
'second is shaking'
>>> foo.wiggle()
'second is wiggling'
>>> 
>>> bar.name
'third'
>>> bar.bop()
'third is bopping'
>>> bar.shake()
'third is shaking'
>>> bar.wiggle()
'third is wiggling'
>>> bar.crunk()
'third is crunking'
>>> 
>>> baz.wiggle()
'This Baz instance, fourth, is wiggling'
>>>

这些示例中的类具有仅对类实例有效的方法属性——方法需要绑定到一个实例。我没有包含任何不需要绑定到实例的类方法或静态方法的示例 - What is the difference between @staticmethod and @classmethod in Python?

有一些很好的答案
>>> A.wiggle
<unbound method A.wiggle>
>>> A.wiggle()

Traceback (most recent call last):
  File "<pyshell#41>", line 1, in <module>
    A.wiggle()
TypeError: unbound method wiggle() must be called with A instance as first argument (got nothing instead)
>>> Bar.crunk
<unbound method Bar.crunk>
>>> Bar.crunk()

Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    Bar.crunk()
TypeError: unbound method crunk() must be called with Bar instance as first argument (got nothing instead)
>>> 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-10
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 2016-02-20
    • 2012-12-11
    相关资源
    最近更新 更多